<template>
  <Transition :name="transitionName">
    <div
      v-show="visible"
      class="vk-message"
      role="alert"
      ref="messageRef"
      @mouseenter="startTimer"
      @mouseleave="clearTimer"
      @enter="updateHeight"
      @after-leave="destroyComponent"
      :style="cssStyle"
      :class="{ 'is-close': showClose, [`vk-message-${type}`]: type }"
    >
      <div class="vk-message__content">
        <slot>
          <RenderVnode :vNode="message" v-if="message"></RenderVnode>
        </slot>
      </div>
      <div class="vk-message__close" v-if="showClose">
        <Icon
          @click.stop="
            ($event) => {
              visible = false;
            }
          "
          icon="xmark"
        ></Icon>
      </div>
    </div>
  </Transition>
</template>

<script setup lang="ts">
import {
  defineProps,
  withDefaults,
  ref,
  onMounted,
  watch,
  computed,
  nextTick,
  defineExpose,
  defineOptions,
} from "vue";
import { MessageProps } from "./types";
import RenderVnode from "../Common/RenderVnode";
import Icon from "../Icon/Icon.vue";
import { getLastBottomOffset, getLastInstance } from "./methods";
import useEventListener from "@/hooks/useEventListener";

defineOptions({
  name: "VkMessage",
});

const props = withDefaults(defineProps<MessageProps>(), {
  type: "info",
  duration: 3000, // 3秒
  offset: 20,
  transitionName: "fade-up",
});

const visible = ref(false);
const messageRef = ref<HTMLDivElement>();

// 计算偏移高度
// 这个 div 的高度
const height = ref(0);
// 上一个实例的最下面的坐标数字，第一个是0
const lastOffset = computed(() => {
  return getLastBottomOffset(props.id);
});
// 这个元素应该使用的 top
const topOffset = computed(() => {
  return height.value + lastOffset.value;
});
// 这个元素为下一个元素预留的 offset，也就是它最低端 bottom 的值
const bottomOffset = computed(() => {
  return height.value + topOffset.value;
});
const cssStyle = computed(() => {
  return {
    top: topOffset.value + "px",
    zIndex: props.zIndex,
  };
});

let timer: any;
function startTimer() {
  if (props.duration === 0) return;
  timer = setTimeout(() => {
    visible.value = false;
  }, props.duration);
}

function clearTimer() {
  clearTimeout(timer);
}

onMounted(async () => {
  visible.value = true;
  startTimer();
  // 拿到dom节点后做以下操作
  //   await nextTick(() => {
  //     // getBoundingClientRect()可以拿到和坐标高度相关的一系列的值
  //     height.value = messageRef.value!.getBoundingClientRect().height;
  //   });
});

function keydown(e: Event) {
  // 将 e 断言成 KeyboardEvent
  const event = e as KeyboardEvent;
  if (event.code === "Escape") {
    visible.value = false;
  }
}

useEventListener(document, "keydown", keydown);

// watch(visible, (newValue) => {
//   if (!newValue) {
//     props.onDestroy; // 如果不显示，则销毁实例
//   }
// });
function destroyComponent() {
  props.onDestroy();
}

function updateHeight() {
  height.value = messageRef.value!.getBoundingClientRect().height;
}

// 把 bottomOffset 暴露出去
defineExpose({
  bottomOffset,
  visible,
});
</script>

<style scoped></style>
